package com.sunlands.zlcx.usercenter.interceptor;

import com.sunlands.zlcx.usercenter.common.HttpHelper;
import com.sunlands.zlcx.usercenter.common.annotation.AuthSig;
import com.sunlands.zlcx.usercenter.exception.BusinessException;
import com.sunlands.zlcx.usercenter.util.SignUtil;
import com.sunlands.zlcx.usercenter.util.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

@Component
public class SignInterceptor extends HandlerInterceptorAdapter {

    @Value("${shangde.sign.secret}")
    String secret;

    @Value("${shangde.sign.testSecret}")
    String testSecret;

    @Value("${sign.devMode}")
    boolean signDevMode;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse httpServletResponse, Object o) throws Exception {

        if(signDevMode){
            return true;
        }

        AuthSig annotation;
        if(o instanceof HandlerMethod) {
            annotation = ((HandlerMethod) o).getMethodAnnotation(AuthSig.class);
        }else{
            return true;
        }

        //如果没有@AuthSig注解，则不验证sig
        if(annotation == null){
            return true;
        }

        String sign = request.getHeader("sign");

        if (testSecret.equalsIgnoreCase(sign) || StringUtil.isEmpty(sign)) {
            return true;
        }

        boolean checkSign = false;
                //根据不同的请求方式判断参数sig--begin
        String method = request.getMethod();
        String contentType = request.getHeader("Content-Type");
        if ("GET".equals(method)) {
            //log.info("SignInterceptor get method ,uri =【{}】, sig = 【{}】, params = 【{}】", request.getRequestURI(), sign, request.getQueryString());
            Map<String, String[]> requestParams =requestToMapObject(request);
            checkSign = SignUtil.verifySign(secret, sign, requestParams);
        }else if(("POST".equals(method) || "PUT".equals(method)) && contentType!=null && contentType.indexOf("multipart") < 0){
            String body = HttpHelper.getBodyString(request);
            if (!StringUtil.isEmpty(body)) {
                checkSign = SignUtil.verifySignJson(secret, sign, body);
                //log.info("post/put method ,uri = 【{}】 , sig = 【{}】, params = 【{}】", request.getRequestURI(), sign, ""+body);
            } else {
                //log.info("SignInterceptor post/put method ,uri =【{}】, sig = 【{}】, params = 【{}】", request.getRequestURI(), sign, request.getQueryString());
                Map<String, String[]> requestParams =requestToMapObject(request);
                checkSign = SignUtil.verifySign(secret, sign, requestParams);
            }

        }else{
            checkSign = true;
            //log.info("SignInterceptor {} method, uri=【{}】, sig = 【{}】unhandled.", method, request.getRequestURI(), sign);
        }

        if (!checkSign) {
            throw new BusinessException("签名错误");
        }
        //根据不同的请求方式判断参数sig--end
        return true;
    }


    /**
     * 判断GET请求的签名
     * @param request
     * @return
     */
    private HashMap<String, String []> requestToMapObject(HttpServletRequest request) {

        HashMap<String, String []> parameterMap = new HashMap<String, String []>();
        Enumeration<String> names = request.getParameterNames();
        if (names != null) {
            Collections.list(names).stream().filter(name -> name != null).forEach(name -> {
                String value = request.getParameter(name);
                if(StringUtils.isNotEmpty(value)){
                    parameterMap.put(name.toString(), new String [] {request.getParameter(name.toString())});
                }else{
                    String[] values = request.getParameterValues(name);
                    parameterMap.put(name.toString(), values);
                }
            });
        }
        return parameterMap;
    }
}
